#include "iostream"
#include <stdio.h>
#include "unistd.h"
#include "cstring"
#include "sys/socket.h"
#include "arpa/inet.h"
#include "signal.h"
#include "errno.h"
#include "json.hpp"

#define SERV_IP "127.0.0.1"
#define SERV_PORT 8000

#define KEY_VALUE_REQUEST 0
using json = nlohmann::json;

std::string Randstr(const int len)
{
    std::string ans;
    int i;
    for (i = 0; i < len; i++)
    {
        char c;
        switch ((rand() % 3))
        {
        case 1:
            c = 'A' + rand() % 26;
            break;
        case 2:
            c = 'a' + rand() % 26;
            break;
        default:
            c = '0' + rand() % 10;
        }
        ans += c;
    }
    ans[++i] = '\0';
    return ans;
}
json KeyValuejs()
{
    json js, data;
    data["flag"] = true;
    data["key"] = Randstr(20);
    data["value"] = Randstr(20);
    js["type"] = KEY_VALUE_REQUEST;
    js["data"] = data;
    return js;
}
int GetIPPort(std::string cacheip){
    int cut = sizeof(cacheip);
    while(cacheip[cut]!=58){
        cut--;
    }
    int port = std::stoi(cacheip.substr(cut+1,sizeof(cacheip)));
    return port;
}

void perr_exit(const char* s){
    perror(s);
    exit(-1);
}
int Socket(int family, int type, int protocol){
    int n;
    if((n=socket(family, type, protocol))<0)
        perr_exit("socket error");
    return n;
}
int Connect(int fd, const struct sockaddr* sa, socklen_t salen){
    int n;
    n = connect(fd, sa, salen);
    if(n<0)
        perr_exit("connect error");
    return n;
}
int Close(int fd){
    int n;
    if((n=close(fd))<0)
        perr_exit("close error");
    return n;
}
ssize_t Read(int fd, char *ptr, size_t nbyte){
    ssize_t n;
    do{
        n = read(fd, ptr, nbyte);
        if(n>=0)
            return n;
    }while(errno==EINTR);
    perr_exit("read error");
    return -1;
}
ssize_t Write(int fd, const void* ptr, size_t nbytes){
    ssize_t n;
    do{
        n = write(fd, ptr, nbytes);
        if(n>=0)
            return n;
    }while(errno==EINTR);
    perr_exit("write error");
    return -1;
}
// void StrCli(FILE *fp, int sockfd){
//     char sendline[BUFSIZ],recvline[BUFSIZ];
//     while(fgets(sendline,BUFSIZ,fp)!=NULL){
//         writen(sockfd,sendline,strlen(sendline));
//         if(readline(sockfd,recvline,BUFSIZ) == 0)
//             err_quit("StrCli:server terminated prematurely");
//         fputs(recvline, stdout);
//     }
// }
void Sleep_ms(int n){
    struct timeval delay;
    delay.tv_sec = 0;
    delay.tv_usec = n * 1000;
    select(0, NULL, NULL, NULL, &delay);
}
int main(int argc, char *argv[]){
    struct sockaddr_in serv_addr;
    socklen_t serv_addr_len;
    signal(SIGPIPE, SIG_IGN);
    int cfd = Socket(AF_INET, SOCK_STREAM, 0);
    bzero(&serv_addr,sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    inet_pton(AF_INET, SERV_IP, &serv_addr.sin_addr.s_addr);
    serv_addr.sin_port = htons(SERV_PORT);
    Connect(cfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
    std::cout << "connect fault?" << std::endl;
    sleep(5);
    int i = 0;
    int n;
    char buff[BUFSIZ];
    while(1){
        sleep(5);
        json js = KeyValuejs();
        auto key = js["data"]["key"].get<std::string>();
        std::string buf = js.dump();
        std::cout << buf << std::endl;
        do{
            n = write(cfd, (char *)buf.data(), buf.length());
            std::cout << std::endl;
            if (n >= 0)
                break;
        } while (errno == EINTR);
        read(cfd, buff, BUFSIZ);
        
        if (n < 0){
            int cflag;
            do
            {
                sleep(1);
                close(cfd);
                std::cout << "cfd closed" << std::endl;
                cfd = Socket(AF_INET, SOCK_STREAM, 0);
                cflag = connect(cfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)); //here cannot use Connect
            } while (cflag < 0);
        }
    }
    
    return 0;
}
